package cipher

import (
	"crypto"
	"crypto/hmac"
	"crypto/md5"
	"crypto/sha1"
	"crypto/sha256"
	"crypto/sha512"
	"golang.org/x/crypto/sha3"
	"hash"
)

const (
	DefaultKey string = "pdc"
)

const (
	HMAC_MD5 crypto.Hash = 100 + iota
	HMAC_SHA1
	HMAC_SHA224
	HMAC_SHA256
	HMAC_SHA384
	HMAC_SHA512
)

type Hash struct {
	t   crypto.Hash
	src []byte
}

type Hmac struct {
	Hash
	key []byte
}

// hash
func (h *Hash) Hash() []byte {
	return _hash(h.t, h.src)
}

// hmac
func (h *Hmac) Hmac() []byte {
	return _hmac(h.t, h.src, h.key)
}

func FHashType(t crypto.Hash) (handle func() hash.Hash) {
	switch t {
	case crypto.MD5:
		handle = md5.New
	case crypto.SHA1:
		handle = sha1.New
	case crypto.SHA224:
		handle = sha256.New224
	case crypto.SHA256:
		handle = sha256.New
	case crypto.SHA384:
		handle = sha512.New384
	case crypto.SHA512:
		handle = sha512.New
	case crypto.SHA3_224:
		handle = sha3.New224
	case crypto.SHA3_256:
		handle = sha3.New256
	case crypto.SHA3_384:
		handle = sha3.New384
	case crypto.SHA3_512:
		handle = sha3.New512
	default:
		handle = sha256.New
	}
	return
}

func HashType(t crypto.Hash) (h hash.Hash) {
	return FHashType(t)()
}

func HmacType(t crypto.Hash, key []byte) (h hash.Hash) {
	if key == nil {
		key = []byte(DefaultKey)
	}
	switch t {
	case HMAC_MD5:
		h = hmac.New(md5.New, key)
	case HMAC_SHA1:
		h = hmac.New(sha1.New, key)
	case HMAC_SHA224:
		h = hmac.New(sha256.New224, key)
	case HMAC_SHA256:
		h = hmac.New(sha256.New, key)
	case HMAC_SHA384:
		h = hmac.New(sha512.New384, key)
	case HMAC_SHA512:
		h = hmac.New(sha512.New, key)
	default:
		h = hmac.New(sha256.New, key)
	}
	return
	return
}

func _hash(t crypto.Hash, src []byte) []byte {
	h := HashType(t)
	h.Write(src)
	return h.Sum(nil)
}

func _hmac(t crypto.Hash, src, key []byte) []byte {
	h := HmacType(t, key)
	h.Write(src)
	return h.Sum(nil)
}

// md5
func MD5(src []byte) ([]byte, error) {
	if src == nil {
		return nil, CError{
			detail: "md5 encrypt bytes is nil",
		}
	}
	return _hash(crypto.MD5, src), nil
}

// sha1
func SHA1(src []byte) ([]byte, error) {
	if src == nil {
		return nil, CError{
			detail: "sha1 encrypt bytes is nil",
		}
	}
	return _hash(crypto.SHA1, src), nil
}

// sha224
func SHA224(src []byte) ([]byte, error) {
	if src == nil {
		return nil, CError{
			detail: "sha224 encrypt bytes is nil",
		}
	}
	return _hash(crypto.SHA224, src), nil
}

// sha256
func SHA256(src []byte) ([]byte, error) {
	if src == nil {
		return nil, CError{
			detail: "sha256 encrypt bytes is nil",
		}
	}
	return _hash(crypto.SHA256, src), nil
}

// sha384
func SHA384(src []byte) ([]byte, error) {
	if src == nil {
		return nil, CError{
			detail: "sha384 encrypt bytes is nil",
		}
	}
	return _hash(crypto.SHA384, src), nil
}

// sha512
func SHA512(src []byte) ([]byte, error) {
	if src == nil {
		return nil, CError{
			detail: "sha512 encrypt bytes is nil",
		}
	}
	return _hash(crypto.SHA512, src), nil
}

// ======================== hmac ==============================
// hmac md5
func HMACMD5(src, key []byte) ([]byte, error) {
	if src == nil {
		return nil, CError{
			detail: "hmac md5 encrypt bytes is nil",
		}
	}
	return _hmac(HMAC_MD5, src, key), nil
}

// hmac sha1
func HMACSHA1(src, key []byte) ([]byte, error) {
	if src == nil {
		return nil, CError{
			detail: "hmac sha1 encrypt bytes is nil",
		}
	}
	return _hmac(HMAC_SHA1, src, key), nil
}

// hmac sha224
func HMACSHA224(src, key []byte) ([]byte, error) {
	if src == nil {
		return nil, CError{
			detail: "hmac sha224 encrypt bytes is nil",
		}
	}
	return _hmac(HMAC_SHA224, src, key), nil
}

// hmac sha256
func HMACSHA256(src, key []byte) ([]byte, error) {
	if src == nil {
		return nil, CError{
			detail: "hmac sha256 encrypt bytes is nil",
		}
	}
	return _hmac(HMAC_SHA256, src, key), nil
}

// hmac sha384
func HMACSHA384(src, key []byte) ([]byte, error) {
	if src == nil {
		return nil, CError{
			detail: "hmac sha384 encrypt bytes is nil",
		}
	}
	return _hmac(HMAC_SHA384, src, key), nil
}

// hmac 512
func HMACSHA512(src, key []byte) ([]byte, error) {
	if src == nil {
		return nil, CError{
			detail: "hmac sha512 encrypt bytes is nil",
		}
	}
	return _hmac(HMAC_SHA512, src, key), nil
}

// ================== sha3 ========================
// sha3_224
func SHA3224(src []byte) ([]byte, error) {
	if src == nil {
		return nil, CError{
			detail: "sha3_224 encrypt bytes is nil",
		}
	}
	return _hash(crypto.SHA3_224, src), nil
}

// sha3_256
func SHA3256(src []byte) ([]byte, error) {
	if src == nil {
		return nil, CError{
			detail: "sha3_256 encrypt bytes is nil",
		}
	}
	return _hash(crypto.SHA3_256, src), nil
}

// sha3_384
func SHA3384(src []byte) ([]byte, error) {
	if src == nil {
		return nil, CError{
			detail: "sha3_384 encrypt bytes is nil",
		}
	}
	return _hash(crypto.SHA3_384, src), nil
}

// sha3_512
func SHA3512(src []byte) ([]byte, error) {
	if src == nil {
		return nil, CError{
			detail: "sha3_512 encrypt bytes is nil",
		}
	}
	return _hash(crypto.SHA3_512, src), nil
}
